package fencer911;

import com.google.zxing.*;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.common.HybridBinarizer;

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.concurrent.Future;
import org.apache.commons.codec.binary.Base64;
/**
 * @author <a href="https://github.com/fencer911/transfer-file-by-qrcode">transfer-file-by-qrcode</a>
 * @since 2020/03
 */
public class FileQrCodeReceiverListener {
    private static Future<?> curTask;
    private static RecRunable taskRun;
    public static void addListeners() {

        FileQrCodeReceiverForm.getInstance().getRecButton().addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if(curTask!=null){
                    curTask.cancel(true);
                    System.out.println("cancel task:"+curTask);
                }
                JButton recBtn=FileQrCodeReceiverForm.getInstance().getRecButton();
                if (FileQrCodeReceiverForm.getInstance().getTransModeScreenRBtn().isSelected())
                {
                    taskRun=recognitionBatch();
                    curTask=App.executor.submit(taskRun);
                }else{
                    JOptionPane.showMessageDialog(App.app, "Only work in Mode (Capture Screen,not selected)", "Tips", JOptionPane.OK_CANCEL_OPTION);
                }

                System.out.println("create task:"+curTask);
            }

        });
        FileQrCodeReceiverForm.getInstance().getUnReceivedButton().addActionListener(new ActionListener(){
            @Override
            public void actionPerformed(ActionEvent e) {
                if(taskRun!=null){
                    FileQrCodeReceiverForm.getInstance().getTextArea().setText(taskRun.findUnReceived());
                }
            }
        });
        FileQrCodeReceiverForm.getInstance().getTransModeFileRBtn().addActionListener(new ActionListener(){
            @Override
            public void actionPerformed(ActionEvent e) {
                chooseImage();
            }
        });
        FileQrCodeReceiverForm.getInstance().getTransModeCameraRBtn().addActionListener(new ActionListener(){
            @Override
            public void actionPerformed(ActionEvent e) {
                JOptionPane.showMessageDialog(App.app, "It will implement in the future", "Tips", JOptionPane.WARNING_MESSAGE);
            }
        });
    }
    private static void chooseImage()  {
        JFileChooser fileChooser = new JFileChooser();
        int approve = fileChooser.showOpenDialog(FileQrCodeReceiverForm.getInstance().getRootPanel());
        if (approve == JFileChooser.APPROVE_OPTION) {
            File selectedFile = new File(fileChooser.getSelectedFile().getAbsolutePath());
            try {
                    String text=recognition(selectedFile);
                    FileQrCodeReceiverForm.getInstance().getTextArea().setText(text);
                }catch (Throwable err){
                    FileQrCodeReceiverForm.getInstance().getTextArea().setText("error:"+err.getMessage());
                }
        }
    }
    public static String recognition(File imageFile) {
        BufferedImage image = null;
        try {
            image = ImageIO.read(imageFile);
        } catch (IOException e2) {
            // TODO Auto-generated catch block
            e2.printStackTrace();
        }
        return recognition(image, true, false);
    }
    public   static  class  RecRunable implements  Runnable{
        private ImagePannel imagePannel;
        Decoder decoder=new Decoder();
        Rectangle captureRect;
        int sleep;

        public RecRunable(ImagePannel imagePannel,Rectangle captureRect, int sleep) {
            this.imagePannel = imagePannel;
            this.decoder = decoder;
            this.captureRect = captureRect;
            this.sleep = sleep;
        }
        public  String findUnReceived(){
            int total=decoder.total;
            StringBuilder  unReceived=new StringBuilder();
            int count=0;
            for(int i=0;i<total;i++){
                if(count>=5000){
                    break;
                }
                if(!decoder.ids.contains(i)){
                    unReceived.append(i+",");
                    count++;
                }
            }
            return unReceived.toString();
        }
        @Override
        public void run() {
            Date start_date=new Date();;
            long start_time=System.currentTimeMillis();
            while(true) {
                try {
                    if(Thread.currentThread().isInterrupted()||decoder.receiveAll) {
                        break;
                    }
                    //show captureImage
                    BufferedImage captureImage= new Robot().createScreenCapture(captureRect);
                    imagePannel.setBufferedImage(captureImage);
                    imagePannel.repaint();
                    //rec
                    String decode=recognition(captureImage, true, false);
                    if(decode!=null&&decode.trim().length()>0) {
                        decoder.receive(Base64.decodeBase64(decode));
                        if(decoder.total!=0) {
                            BigDecimal pec = new BigDecimal(decoder.size).divide(new BigDecimal(decoder.total), 2, RoundingMode.CEILING);
                            FileQrCodeReceiverForm.getInstance().getTipLabel().setText(decoder.total + "/" + decoder.size + "/" + pec.toString());
                        }
                    }
                } catch (Throwable ex) {
                    FileQrCodeReceiverForm.getInstance().getTipLabel().setText(decoder.curIndex+"/error:"+ex.getMessage());
                    ex.printStackTrace();
                }
                try {// sleep for wait sender process
                    Thread.sleep(sleep);
                } catch (InterruptedException interruptedException) {
                    System.out.println("interruptedException"+Thread.currentThread().isInterrupted());
                    Thread.currentThread().interrupt();
                    System.out.println("interrupted"+Thread.currentThread().isInterrupted());
                }
            }
            if(decoder.receiveAll) {
                //save
                String timeName=new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());;
                File f=new File("./received_"+timeName);
                FileQrCodeReceiverForm.getInstance().getTextArea().setText("received file save to:"+f.getAbsolutePath());
                saveFile(decoder.dataArray,f);
            }
        }
    }
    public static RecRunable recognitionBatch() {
        String[] rect=FileQrCodeReceiverForm.getInstance().getCaptureRectTextField().getText().trim().split(",");
        final int x=Integer.parseInt(rect[0]);
        final int y=Integer.parseInt(rect[1]);
        final int width=Integer.parseInt(rect[2]);
        final int height=Integer.parseInt(rect[3]);
        Rectangle captureRect=new Rectangle(x,y,width,height);
        ImagePannel imagePannel=FileQrCodeReceiverForm.getInstance().getLeftPanel();

        int sleep=Integer.parseInt(FileQrCodeReceiverForm.getInstance().getIntervalTextField().getText());




        return new RecRunable(imagePannel,captureRect,sleep);
    }
    public static String recognition(BufferedImage image, boolean isTryHarder, boolean isPureBarcode) {

        final MultiFormatReader formatReader = new MultiFormatReader();

        final LuminanceSource source = new BufferedImageLuminanceSource(image);
        final Binarizer binarizer = new HybridBinarizer(source);
        final BinaryBitmap binaryBitmap = new BinaryBitmap(binarizer);

        final HashMap<DecodeHintType, Object> hints = new HashMap<DecodeHintType, Object>();
        hints.put(DecodeHintType.CHARACTER_SET, "UTF-8");
        // 优化精度
        hints.put(DecodeHintType.TRY_HARDER, Boolean.valueOf(isTryHarder));
        // 复杂模式，开启PURE_BARCODE模式
        hints.put(DecodeHintType.PURE_BARCODE, Boolean.valueOf(isPureBarcode));
        Result result;
        try {
            result = formatReader.decode(binaryBitmap, hints);
        } catch (NotFoundException e) {
            // 报错尝试关闭复杂模式
            hints.remove(DecodeHintType.PURE_BARCODE);
            try {
                result = formatReader.decode(binaryBitmap, hints);
            } catch (NotFoundException e1) {
                e1.printStackTrace();
                throw new QrCodeException(e1);
            }
        }
        return result.getText();
    }
    public static void saveFile(byte[][] data, File file) {
        // 创建String对象保存文件名路径
        try {
            // 创建指定路径的文件
            // 如果文件不存在
            if (file.exists()) {
                // 创建新的空文件
                file.delete();
            }
            file.createNewFile();
            // 获取文件的输出流对象
            FileOutputStream outStream = new FileOutputStream(file);
            // 获取字符串对象的byte数组并写入文件流
            for (int i = 0; i < data.length; i++) {
                outStream.write(data[i]);
            }
            outStream.flush();
            outStream.close();
            // 最后关闭文件输出流
            outStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}
